import hist_similar
import math
import os
import config

'''
传入：
    本函数需要由界面传来目标检索图片的路径object，和用户选中的图片的地址列表str_cho
    object传给类Bayes（声明类时初始化加载），str_cho传给函数bayes_judge（调用函数时传递）
传出：
    传给界面的是一个包含目标图片地址和概率的二维列表，如[[地址1, 概率1], [地址2, 概率2], ……]
    该列表是根据概率值从大到小排序的，界面只需要提取该列表前六项的地址进行显示即可
    按钮“初始化检索”调用函数init_probability(无需传参)，返回值为上述的二维列表
    按钮“选中图片，继续检索！”调用函数bayes_judge(需要传参str_cho)，返回值为重新计算并排序的二维列表
    按钮“检索结果满意，退出检索系统！”退出程序即可
'''


# object是目标图片的路径，由界面用户操作后传来
class Bayes(object):
    # 初始化函数，生成检索图像的范围
    def __init__(self, init_image: str, image_dir: str):
        # 任何数据都要有校验
        if not os.path.exists(init_image):
            raise FileNotFoundError
        init_image = os.path.abspath(init_image)

        if not os.path.exists(image_dir):
            raise FileNotFoundError
        image_dir = os.path.abspath(image_dir)

        # 赋值路径
        self.goal = init_image
        # 遍历目标文件夹，生成检索范围地址的列表
        self.ri = list()
        for root, dirs, files in os.walk(image_dir):
            for name in files:
                # ::tutu:: 验证文件的扩展名，防止非图片文件来捣乱
                _, _ext = os.path.splitext(name)
                if _ext:
                    if _ext[1:].lower() in config.allowed_extensions:
                        # \\转换为/
                        self.ri.append(os.path.join(root, name).replace('\\', '/'))

        # 保存图库中每张图为目标图像概率的列表
        self.pvalue = list()
        # 有图片地址和图片概率的二维列表
        self.target = list()
        # 初始化概率
        # self.init_probability()
        # 贝叶斯反馈
        # self.bayes_judge()

    # 初始化概率
    def init_probability(self):
        for i in self.ri:
            p = hist_similar.calc_similar_by_path(i, self.goal)
            self.pvalue.append(p)
        # 合并概率和图片的地址列表
        self.target = list(zip(self.ri, self.pvalue))  # ::tutu::  zip 后列表内的是tuple, tuple是immutable的，即不可更改
        self.target = [list(i) for i in self.target]  # ::tutu:: 增加此行 避免 TypeError: 'tuple' object does not support item assignment，注意tuple是 immutable 的
        self.p_sort()
        return self.target

    # 贝叶斯反馈，str_cho是由用户传来的选中的图像地址列表
    def bayes_judge(self, str_cho):
        # print(str_cho)
        flag = 0
        for i in self.ri:
            score = 0
            idx = 0
            for j in self.ri:
                if i != j:
                    if hist_similar.calc_similar_by_path(self.goal, i) > hist_similar.calc_similar_by_path(self.goal, j):
                        score = score + 1
                    elif hist_similar.calc_similar_by_path(self.goal, i) == hist_similar.calc_similar_by_path(self.goal, j):
                        score = score + 0.5
            p = 1 / (1 + math.exp((20 - score) / -10))
            # print('score=' + str(score))
            # print('p=' + str(p))
            for cho in str_cho:
                if i == cho:
                    flag = 1
                    break
            for m in self.target:
                if i == m[0]:
                    break
                idx = idx + 1
            if flag == 1:
                # ::tutu:: 避免 TypeError: 'tuple' object does not support item assignment，注意tuple是 immutable 的
                self.target[idx][1] = self.target[idx][1] * p
                # print(u'该图片被用户选中')
            else:
                # ::tutu:: 避免 TypeError: 'tuple' object does not support item assignment，注意tuple是 immutable 的
                self.target[idx][1] = self.target[idx][1] * (1 - p)
        self.p_sort()
        return self.target

    # 将概率从大到小排序
    def p_sort(self):
        self.target = sorted(self.target, key=lambda x: x[1], reverse=True)
        return 0

    def get_top_6(self):
        return [i[0] for i in self.target][:6]


if __name__ == '__main__':
    b = Bayes(image_dir='images', init_image='images/1.jpg')
    b.init_probability()
    t6 = b.get_top_6()
    print(t6)
    b.bayes_judge([t6[2:5]])
    t6 = b.get_top_6()
    print(t6)